# coding=utf-8
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.db import connection, transaction
from django import forms

def select(query, params=()):
    cursor = connection.cursor()
    if params:
        cursor.execute(query, params)
    else: 
        cursor.execute(query)
    return cursor.fetchall()

def selectDict(query, fields, params=(), escape=False):
    """Bierze string postaci
    'SELECT {fields} FROM KinoRezerwacja_film WHERE cośtam',
    pola (m. in. do wstawienia w {fields}) i zwraca wynik zapytania
    jako listę słowników. params to argumenty do query."""
    queryFields = fields
    if escape:
        queryFields = ['"{0}"'.format(f) for f in fields]
    tmp = select(query.format(fields=", ".join(queryFields)), params)
    res = []
    for row in tmp:
        r = {}
        for i in range(len(fields)):
            r[fields[i]] = row[i]
        res.append(r)
    return res

def selectOne(query, fields=None, params=(), escape=False ):
    """Zwraca jeden wiersz z wyniku zapytania.
    Jeśli zapytanie nie zwróciło nic, zwraca None.
    Jeśli fields jest ustawione, to wynik będzie
    takiej postaci jak w selectDict."""
    if fields is None:
        res = select(query, params)
    else:
        res = selectDict(query, fields, params, escape)
    if res:
        return res[0]
    else:
        return None
        
def getUser(request, id=None):
    if id is None:
        if 'userId' not in request.session:
            return None
        else:
            id = request.session['userId']
    user = selectOne('SELECT {fields} FROM KinoRezerwacja_Klient WHERE id = %s', ('id', 'login', 'imie', 'nazwisko'), (id,))
    if user:
        user['admin'] = bool(selectOne("SELECT czy_uzytkownik_jest_adminem(%s)", params=(user['id'],))[0])
    return user

def loginDecorator(function, admin=False):
    def newFunction(request, *args, **kwargs):
        try:
            user = getUser(request)
            if not user:
                return HttpResponseRedirect('/KinoRezerwacja/login/'+request.path)
            if admin and not user['admin']:
                return HttpResponseForbidden('Tylko dla adminów')
            return function(request, *args, **kwargs)
        except:
            return HttpResponseForbidden('Nie możesz')
    return newFunction

def withLoggedUser(function):
    return loginDecorator(function)

def withLoggedAdmin(function):
    return loginDecorator(function, True)

def commit(query, params=(), fetch=False):
    cursor = connection.cursor()
    if params:
        cursor.execute(query, params)
    else: 
        cursor.execute(query)
    res = None
    if fetch:
        res = cursor.fetchall()
    transaction.commit_unless_managed()
    return res

def render(template, arguments, request=None, login=True, **kwargs):
    """Renderuje template'a dodając ficzery do logowania."""
    if request and login:
        arguments['user'] = getUser(request)
        if 'admin_userId' in request.session:
            arguments['admin_user'] = getUser(request, id=request.session['admin_userId'])
        arguments['loginRedirect'] = arguments['logoutRedirect'] = request.path
    return render_to_response(template, arguments, **kwargs)

def handleForm(request, formClass, title, handleOk, emptyForm=None, checkFunction=None, errorText=None): 
    error = None 
    if request.method == 'POST':
    	form = formClass(request.POST)
        if form.is_valid() and (not checkFunction or checkFunction(form)):
            return handleOk(form)
        else:
            error = errorText
    else:
        if emptyForm is None:
            form = formClass()
        else:
            form = emptyForm
    return render('KinoRezerwacja/dodaj.html', {'form':form, 'title':title, 'error':error, 'action':request.path,}, request, context_instance=RequestContext(request))

def getUserId(request):
    user = getUser(request)
    if not user:
        return None
    if user['admin'] and 'admin_userId' in request.session:
        return request.session['admin_userId']
    return user['id']

def handleAddForm(request, formClass, table, insertFields=None, title=None, redirect='/KinoRezerwacja/', escape=False, query=None, updateId=None, checkFunction=None, errorText=None, additionalFunction=(lambda x:None), emptyForm=None):
    """Obsługuje formę dodającą coś do tabeli table.
    Nazwy pól w formie muszą zgadzać się z tymi w tabeli.
    Jeśli query jest niepuste, to jest wykonywane z parametrami
    będącymi wartościami pól formy dla insertFields.
    Jeśli updateId jest ustawione, to zamiast inserta będzie update.
    """
    if not title:
    	title = table
    def handle(form, insertFields=insertFields, query=query, escape=escape, redirect=redirect, table=table):
        if not insertFields:
            insertFields = list(form.cleaned_data.keys())
        fields = insertFields
        if escape:
            insertFields = [ '"{0}"'.format(f) for f in insertFields ]
        vals = list(map((lambda x:form.cleaned_data[x]), fields))
        if not query:
            if updateId is not None:
                query = 'UPDATE {table} SET {vals} WHERE id=%s'.format(
                        table=table, vals=', '.join(["{0}=%s".format(f) for f in insertFields ]) )
                vals += [updateId]
            else:
                query = 'INSERT INTO {table} ({fields}) VALUES ({vals})'.format(table=table, fields=", ".join(insertFields), vals=', '.join(['%s' for i in insertFields]))
        commit(query, vals)
        additionalFunction(form)
        return HttpResponseRedirect(redirect)
    if emptyForm is None and updateId is not None:
        emptyForm = formClass(data=selectOne('SELECT {fields} FROM '+table+' WHERE id = %s', insertFields, (updateId,), escape=escape) )
    return handleForm(request, formClass, title, handle, emptyForm, checkFunction=checkFunction, errorText=errorText)

class HiddenField(forms.Field):
    def __init__(self, **kwargs):
        forms.Field.__init__(self, widget=forms.HiddenInput, **kwargs)
        self._value = kwargs["initial"]
    def clean(self, value):
        if value == self._value:
            return value
        raise forms.ValidationError('Nie haksuj mi tu "{0}"'.format(value))

def handleShow(request, table, fields, usunUrl, baseUrl, begin=0, limit=50, dodaj=None, title=None, headers=None, adminMore=None, zmien=None):
    count = selectOne("SELECT count(*) FROM {table}".format(table=table))[0]
    rows = select("SELECT id,{fields} FROM {table} ORDER BY id LIMIT {limit} OFFSET {begin}".format(fields=", ".join([ '"{0}"'.format(f) for f in fields]), table=table, limit=limit, begin=begin))
    rows = [ {'fields':r[1:], 'id':r[0]} for r in rows ]
    next = prev = None
    if begin+limit < count:
        next = "{0}/{1}/{2}/".format(baseUrl, begin+limit, limit)
    if begin>0:
        prev = "{0}/{1}/{2}/".format(baseUrl, max(0,begin-limit), limit)
    if not headers:
        headers=fields
    if not adminMore:
        adminMore = []
    if dodaj:
        adminMore.append({'href':dodaj[0], 'label':dodaj[1]})
    if not title:
        title = table
    return render("KinoRezerwacja/tabela.html", {'prev':prev, 'next':next, 'headers':headers, 'title':title, 'rows':rows, 'usun':usunUrl, 'adminMore':adminMore, 'zmien':zmien}, request)

def getAllFields(table, noId=False):
    res = [ ((f.db_column if f.db_column else f.name), f.verbose_name) for f in table._meta._fields() ]
    if noId:
        res = [r for r in res if r[0]!= 'id']
    return res

def handleGenericShow(request, table_model, begin=0, limit=50, usun=None , dodaj=None, dodajName=None, adminMore=None, zmien=None):
    if usun:
        usun = '/KinoRezerwacja/usun'+usun
    if zmien:
        zmien = '/KinoRezerwacja/zmien'+zmien
    if not dodajName:
        dodajName=dodaj
    if dodaj:
        dodaj = ('/KinoRezerwacja/dodaj'+dodaj+'/', 'Dodaj '+dodajName)
    path = '/KinoRezerwacja/'+request.path.split('/')[2]
    fd = getAllFields(table_model)
    fields=[f[0] for f in fd]
    headers=[f[1] for f in fd]
    return handleShow(request, table_model._meta.db_table, fields, usun, path , int(begin), int(limit), dodaj=dodaj, title=table_model._meta.verbose_name_plural.title(), headers=headers, adminMore=adminMore, zmien=zmien)

def handleRemove(table, id, redirect):
    query='DELETE FROM {table} WHERE id=%s'.format(table=table)
    commit(query, (id,))
    return HttpResponseRedirect(redirect)
